package base

class Sample{
    fun sum(a: Int, b: Int): Int {
        return a + b
    }

/*fun base.main(args: Array<String>) {
    print("sum of 3 and 5 is")
    println(sum(3, 5))
}*/

    //假如返回值是单个表达式,则可以这样写:
    fun sum1(a: Int, b: Int) /*使用'='连接返回结果*/= a + b

    /*
    fun base.main(args:Array<String>){
        println("sum of 19 and 23 is ${sum1(19,23)}")
    }*/
    //无意义返回值:Unit==>可省略
    fun printSum(a:Int,b: Int):Unit {
//    fun printSum(base.getA:Int,b: Int) {//和这个效果一致
        //直接将变量与字符串拼接
        println("sum of $a and $b is ${a+b}")
    }

/*fun base.main(args: Array<String>) {
    printSum(-1,8)
}*/

    fun printSum2(a: Int,b: Int){
        println("sum of $a and $b is ${a+b}")
    }

    fun main(args: Array<String>) {
        printSum2(-3,5)
    }

    fun double(x:Int):Int{
        return 1
    }

    val result = double(2)
    //入参赋默认值
    fun my(a:Array<Byte>,off:Int=0,len:Int=a.size){

    }
}
//给Int增加扩展函数//也是有作用域的..
infix fun Int.mytest(x:Int):Int{
    return 2
}
/*fun base.main(args: Array<String>) {
    print(3 base.mytest 2)
}*/

//继承时 覆盖方法会使用基类方法的默认参数值
//当覆盖基类方法的时候,必须从签名中省略默认参数值(无论父类方法的入参是否有默认值)

open class A{
    open fun foo(i: Int,j:Int=10){
        println("base.getI is $i and j is $j");
    }
}
class B : base.A(){
    //若此时给i赋默认值,则编译不通过..
//    override fun base.foo(base.getI: Int=10,j:Int) {
//    override fun base.foo(base.getI: Int,j:Int=10) {
    override fun foo(i: Int,j:Int) {
        super.foo(i, j);
    }

}

/*fun base.main(args: Array<String>) {
    base.B().base.foo(1,2)
    base.B().base.foo(1)
}*/

fun reformat(str: String,
             normalizeCase: Boolean=true,
             upperCaseFirstLetter: Boolean=true,
             divideByCamelHumps: Boolean=false,
             wordSeparator: Char=' '){
    println(str+wordSeparator+normalizeCase+wordSeparator+upperCaseFirstLetter+wordSeparator+divideByCamelHumps)
}

/*fun base.main(args: Array<String>) {
    base.reformat("你好")
    base.reformat("你好",false)
    base.reformat("你好",false,true,true,'&')
    //使用命名参数使代码更具可读性。
    base.reformat(str="你好",
            normalizeCase = false,
            upperCaseFirstLetter = true,
            divideByCamelHumps = true,
            wordSeparator = '&')
    //可以根据名称来调用,这样就可以省略中间其它参数了!
    base.reformat("哈哈",wordSeparator = '|')
}*/

//vararg可变数量的入参(类似于js的arguments)
fun <T> asList(vararg ts: T): List<T> {
    val result = ArrayList<T>()
    for (t in ts) {//ts is an Array//type is Array <out T>
        print(t.toString()+"  ")
        result.add(t)
    }
    return result;
}

/*fun base.main(args: Array<String>) {
    val list = arrayOf(1,2,3)
    val list2 = base.asList(Unit,2,base.Sample())
    //使用'*'(伸展操作符),代表使用该数组中的每一个元素
    val list3 = base.asList(Unit,2,*list,base.Sample())
    //为什么传入*list2不行==>'*'只适用于Array...
//    val list4 = base.asList(Unit,2,*list2,base.Sample())
}*/

//局部函数
fun test(arr: Array<String>){
    val a=1
    fun test(current: Array<String>,visited: MutableSet<Array<String>>){
        if(!visited.add(current))return;
        for (one in current)
            test(current,visited)
        println("也可以在内部访问外部的参数$a")
    }
    val visited=HashSet<Array<String>>()
    fun test2(current: Array<String>){
        if(!visited.add(current))return;
        for (one in current)
            test(current,visited)//访问外部的visited
    }
    test(arr,HashSet())//调用这个局部函数
    test2(arr)
}

//覆盖方法
//kotlin中需要对可以覆盖的成员标注为open,覆盖后的方法标注为override
// ,也就是必须要显式标注
//类和方法都要标注open,未标注open的类就是final类
open class Base{
    open fun v(){}
    open fun forbidOverride(){}
    fun nv(){}
}
class Derived: base.Base(){
//    fun v(){}//如果没标注override,编译报错
    override fun v() {}

    final override fun forbidOverride() {}//使用final来禁止继续覆盖
}
interface IBASE{//接口方法默认就是open
    fun v(){}
}
class SubDerived: base.Base(), base.IBASE {
    override fun v() {
        super<base.Base>.v()//super<要调用的父类>
    }
}

//中缀表示法
//1.是成员函数或扩展函数
//2.只有一个参数
//3.用infix关键字标注
infix fun Int.addTwo(x: Int): Int{
    return x+2
}

fun main(args: Array<String>) {
    val x = 1 addTwo 2
    //等同于
    val x2 = 1.addTwo(2)
    val l = java.util.concurrent.locks.ReentrantLock()
    base.lock(l) {
        //do something...
    }
}

//内联inline//TODO:使用场景未知..
inline fun <T> lock(lock: java.util.concurrent.locks.Lock, body: () -> T): T {
    lock.lock()
    try{
        return body()
    }finally {
        lock.unlock()
    }

}

//尾递归函数
//函数必须将其自身调用作为它执行的最后一个操作
tailrec fun findFixPoint(x: Double = 1.0): Double
            = if(x==Math.cos(x)) x else base.findFixPoint(Math.cos(x))
//等同于下面这个
fun findFixPoint2(x: Double = 1.0): Double {
    var x = 1.0
    while(true){
        val y = Math.cos(x)
        if(x == y) return y
        x = y
    }
}


fun dfs(){//局部函数
    val visited = HashSet<String>()
    fun dfs(current: String){
        if(!visited.add(current)) return//可以访问外部的visited参数
    }
}

//函数引用


//在 Kotlin 中调用 Java 代码